#pragma once

#include <iostream>
#include <memory>
#include <unordered_map>
#include "Epoller.hpp"
#include "Connection.hpp"
#include "Socket.hpp"
#include "Mutex.hpp"

using namespace SocketModule;

class Reactor
{
    static const int revs_num = 128;

private:
    bool IfConnectionExists(std::shared_ptr<Connection> &conn)
    {
        auto iter = _connections.find(conn->GetFd());
        if (iter == _connections.end())
        {
            return false;
        }
        else
        {
            return true;
        }
    }

    bool IfConnectionExists(int sockfd)
    {
        auto iter = _connections.find(sockfd);
        if (iter == _connections.end())
        {
            return false;
        }
        else
        {
            return true;
        }
    }

    void Dispatcher(int timeout)
    {
        // 从就绪事件队列中获取就绪的事件
        int n = _epoller_ptr->WaitEvents(_revs, revs_num, timeout);
        for (int i = 0; i < n; i++)
        {
            int sockfd = _revs[i].data.fd;
            uint32_t revents = _revs[i].events;
            // 这样一旦有新链接到来的话，就可以多态式的调用相应方法
            if (revents & EPOLLIN)
            {
                if (IfConnectionExists(sockfd))
                    _connections[sockfd]->Recver();
            }
            else if (revents & EPOLLOUT)
            {
                if (IfConnectionExists(sockfd))
                    _connections[sockfd]->Sender();
            }
            // 将所有的异常处理转化成IO错误，将所有的IO错误转化成一个异常处理函数
            else if (revents & EPOLLHUP)
            {
                revents |= (EPOLLIN | EPOLLOUT);
            }
            else if (revents & EPOLLERR)
            {
                revents |= (EPOLLIN | EPOLLOUT);
            }
        }
    }

public:
    Reactor()
        : _epoller_ptr(std::make_unique<Epoller>()), _isrunning(true)
    {
    }

    void Start()
    {
        int timeout = -1;
        if (_connections.empty())
        {
            return;
        }
        _isrunning = true;
        while (_isrunning)
        {
            Dispatcher(timeout);
        }
        _isrunning = false;
    }

    void AddConnection(std::shared_ptr<Connection> &conn)
    {
        // 0、防止重复添加
        if (IfConnectionExists(conn))
        {
            return;
        }

        // 1、将新链接添加到_connections，然后添加到内核当中
        uint32_t events = conn->GetEvents();
        int sockfd = conn->GetFd();
        _epoller_ptr->AddEvent(sockfd, events);

        //2、设置当前链接的拥有者tcpserver的回指指针
        conn->SetOwner(this);

        // 3、将listensock添加到我们的_connections
        _connections[sockfd] = conn;
    }

    void DelConnection(int sockfd)
    {
        //1、先将fd从epoller中移除，因为fd只支持移除合法fd
        _epoller_ptr->DelEvent(sockfd);

        //2、将fd从_connections中移除
        _connections.erase(sockfd);

        //3、关闭文件描述符
        close(sockfd);
    }

    void EnableReadWrite(int sockfd, bool enableread, bool enablewrite)
    {
        //开启读写事件关心
        if(!IfConnectionExists(sockfd))
        {
            return;
        }

        //修改当前sockfd对应的connection关心的事件
        uint32_t new_event = (EPOLLET | (enableread ? EPOLLIN : 0) | (enablewrite ? EPOLLOUT : 0));
        _connections[sockfd]->SetEvent(new_event);

        //写透到内核sockfd对特定事件的关心
        _epoller_ptr->ModEvent(sockfd, new_event);
    }

    ~Reactor()
    {
    }

private:
    // 1、epoll模型
    std::unique_ptr<Epoller> _epoller_ptr;

    // 2、listener获取新链接
    // std::shared_ptr<Listener> _listener_ptr;

    // 3、管理所有的connection，本质是管理所有链接及其专属读写缓冲区
    std::unordered_map<int, std::shared_ptr<Connection>> _connections;

    // 4、是否启用标识位
    bool _isrunning;

    // 5、存放所有就绪事件的容器
    struct epoll_event _revs[revs_num];
};

/*
将reactor与多进程多线程结合：
不是让一个进程、一个线程拥有一个fd，而是一个执行流一个reactor，
One thread one loop(OTOL)
*/